﻿using System;
using System.Collections.Generic;
using System.Linq;
using DDDSample.Application.Repositories;
using DDDSample.Application.Routing;
using DDDSample.Domain.Cargo;
using DDDSample.Domain.Location;
using NHibernate;
using NHibernate.Linq;

namespace DDDSample.Application.Book
{
    public class BookService : IBookService
    {
        private readonly ISession _session;
        private readonly IRoutingService _routingService;

        public BookService(ISession session, IRoutingService routingService)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (routingService == null)
            {
                throw new ArgumentNullException("routingService");
            }
            _session = session;
            _routingService = routingService;
        }

        public Cargo Find(Guid id)
        {
            return _session.Get<Cargo>(id);
        }

        public IList<Cargo> FindAll()
        {
            return _session.Query<Cargo>().ToList();
        }

        public Location FindLocation(UnLocode locode)
        {
            return _session.FindLocation(locode);
        }

        public IList<Location> ListShippingLocations()
        {
            return _session.Query<Location>().ToList();            
        }

        public Guid BookNewCargo(UnLocode originUnLocode, UnLocode destinationUnLocode, DateTime arrivalDeadline)
        {
            var origin = _session.FindLocation(originUnLocode);
            var destination = _session.FindLocation(destinationUnLocode);
            var routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);
            var cargo = new Cargo(routeSpecification);
            return (Guid)_session.Save(cargo);
        }

        public IList<Itinerary> RequestPossibleRoutesForCargo(Guid cargoId)
        {
            var cargo = _session.Get<Cargo>(cargoId);
            return _routingService.FetchRoutesForSpecification(cargo.RouteSpecification);
        }

        public void AssignCargoToRoute(Guid cargoId, Itinerary itinerary)
        {
            var cargo = _session.Get<Cargo>(cargoId);
            cargo.AssignToRoute(itinerary);
        }

        public void ChangeDestination(Guid cargoId, UnLocode unLocode)
        {
            var cargo = _session.Get<Cargo>(cargoId);
            var destination = _session.FindLocation(unLocode);

            var origin = cargo.RouteSpecification.Origin;
            var deadline = cargo.RouteSpecification.ArrivalDeadline;
            var routeSpecification = new RouteSpecification(origin, destination, deadline);
            cargo.SpecifyNewRoute(routeSpecification);
        }
    }
}